/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/10 10:31
  *
  * @file       hd_oled.h
  * @brief      Header file of OLED hardware driver.
  *
  * @note       This file contains the OLED object declaration.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date           Author       Notes
  *   2024/6/10      Chris        the first version
  *
  ******************************************************************************
  */

#ifndef JLC_SKY_OLED_H
#define JLC_SKY_OLED_H

#include <stdarg.h>
#include <stdio.h>
#include "hd_oled_font.h"
#include "hd_oled_protocol.h"


struct OLEDVtbl;

/** @defgroup Object properties
  * @{
  */
typedef struct {
    OLEDProtocol *protocol; /* The protocol of OLED communication(I2C/SPI).     */
    OLEDFont *font;         /* The oled font storage.                           */
    uint8_t size;           /* The font size can be 12/16/24.                   */
    uint8_t mode;           /* The font mode can be negative or positive.       */

    struct OLEDVtbl const *vptr;
} OLED;
/**
  * @}
  */

/** @defgroup Object virtual table
  * @{
  */
struct OLEDVtbl {
    void (*init)(const OLED *this);

    void (*clear)(const OLED *this);

    void (*full)(const OLED *this);

    void (*refresh)(const OLED *this);

    uint8_t (*show_char)(const OLED *this, uint8_t x, uint8_t y, char chr);

    void (*show_string)(const OLED *this, uint8_t x, uint8_t y, char *str);

    void (*show_num)(const OLED *this, uint8_t x, uint8_t y, uint32_t num, uint8_t len);

    void (*show_signed_num)(const OLED *this, uint8_t x, uint8_t y, int32_t num, uint8_t len);

    void (*show_hex_num)(const OLED *this, uint8_t x, uint8_t y, uint32_t num, uint8_t len);

    void (*show_bin_num)(const OLED *this, uint8_t x, uint8_t y, uint32_t num, uint8_t len);

    void (*show_float_num)(const OLED *this, uint8_t x, uint8_t y, float num, uint8_t len);

    uint8_t (*show_chinese)(const OLED *this, uint8_t x, uint8_t y, char *cn);

    void (*show_image)(const OLED *this, uint8_t x, uint8_t y,
                       uint8_t width, uint8_t height, const uint8_t *dotMatrix);

    void (*printf)(const OLED *this, uint8_t x, uint8_t y, char *format, ...);

    void (*draw_point)(const OLED *this, uint8_t x, uint8_t y, uint8_t point);
};
/**
  * @}
  */

/** @defgroup Object constructor and member function
  * @{
  */
void OLED_constructor(OLED *oled, OLEDProtocol *oledProtocol, OLEDFont *oledFont);

static inline void OLED_setSize(OLED *this, const uint8_t size) {
    this->size = size;
}

static inline void OLED_setMode(OLED *this, const uint8_t mode) {
    this->mode = mode;
}
/**
  * @}
  */

/** @defgroup Object virtual table function implementation
  * @{
  */
static inline void OLED_init(const OLED *this) {
    this->vptr->init(this);
}

static inline void OLED_clear(const OLED *this) {
    this->vptr->clear(this);
}

static inline void OLED_full(const OLED *this) {
    this->vptr->full(this);
}

static inline void OLED_refresh(const OLED *this) {
    this->vptr->refresh(this);
}

static inline void OLED_showString(const OLED *this, const uint8_t x, const uint8_t y, char *str) {
    this->vptr->show_string(this, x, y, str);
}

static inline void OLED_showFloat(const OLED *this, const uint8_t x, const uint8_t y, const float num, const uint8_t len) {
    this->vptr->show_float_num(this, x, y, num, len);
}

static inline void OLED_showChinese(const OLED *this, const uint8_t x, const uint8_t y, char *cn) {
    this->vptr->show_chinese(this, x, y, cn);
}

static inline void OLED_showImage(const OLED *this, const uint8_t x, const uint8_t y,
                                  const uint8_t width, const uint8_t height, const uint8_t *dotMatrix) {
    this->vptr->show_image(this, x, y, width, height, dotMatrix);
}

static inline void OLED_printf(const OLED *this, const uint8_t x, const uint8_t y, char *format, ...) {
    char result[16] = {0};
    va_list arg;

    va_start(arg, format);
    vsprintf(result, format, arg);
    va_end(arg);

    this->vptr->show_string(this, x, y, result);
}

static inline void OLED_drawPoint(const OLED *this, const uint8_t x, const uint8_t y, const uint8_t point) {
    this->vptr->draw_point(this, x, y, point);
}
/**
  * @}
  */


/**
 * The mode of the font displayed on the OLED.
 */
#define OLED_MODE_NEGATIVE     0        /* OLED negative display, light up the background.  */
#define OLED_MODE_POSITIVE     1        /* OLED positive display, light up the content.     */

/**
 * The size of the font displayed on the OLED.
 */
#define OLED_SIZE_12          12        /* ascii 12x6, chinese 12x12                        */
#define OLED_SIZE_16          16        /* ascii 16x8, chinese 16x16                        */
#define OLED_SIZE_24          24        /* ascii 24x12, chinese 24x24                       */

#define OLED_I2C_ADDRESS    0x3C        /* OLED address just for I2C.                       */
#define OLED_I2C_CMD        0x00        /* OLED send a connmad.                             */
#define OLED_I2C_DATA       0x40        /* OLED send a data.                                */


#endif // JLC_SKY_OLED_H
